/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 */

package com.huawei.housekeeper.exception;

import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;

import com.google.common.collect.ImmutableMap;
import com.huawei.housekeeper.exception.ArgumentException;
import com.huawei.housekeeper.exception.BusinessException;
import com.huawei.housekeeper.enums.ErrorCode;

import lombok.extern.log4j.Log4j2;
import reactor.core.publisher.Mono;

/**
 * 全局异常处理类
 */
@Log4j2
public class GlobalErrorHandler extends AbstractErrorWebExceptionHandler {

    public GlobalErrorHandler(ErrorAttributes errorAttributes, WebProperties.Resources resourceProperties,
        ApplicationContext applicationContext) {
        super(errorAttributes, resourceProperties, applicationContext);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(),
            request -> renderErrorResponse(request, errorAttributes.getError(request)));
    }

    private Mono<ServerResponse> renderErrorResponse(ServerRequest request, Throwable throwable) {
        int code = ErrorCode.UNKNOWN.getCode();
        if (throwable instanceof BusinessException) {
            BusinessException business = (BusinessException) throwable;
            code = business.getCode();
            log.error(throwable.getMessage(), throwable);
        } else if (throwable instanceof ArgumentException) {
            ArgumentException argument = (ArgumentException) throwable;
            code = argument.getCode();
            log.warn(throwable.getMessage(), throwable);
        } else {
            // 输出异常堆栈信息
            log.error(throwable.getMessage(), throwable);
        }
        String message = throwable.getMessage();
        message = StringUtils.isEmpty(message) ? ErrorCode.UNKNOWN.getMessage() : message;
        return ServerResponse.status(HttpStatus.OK)
            .contentType(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromValue(ImmutableMap.builder().put("code", code).put("message", message).build()));
    }
}